// Author: wsfuyibing <682805@qq.com>
// Date: 2025-05-30

package goods

import (
	"context"
	"fmt"
	"gitee.com/go-libs/db-xorm/db"
	"server/app/errs"
	"server/app/http/models"
	"server/app/http/services"
	"server/app/kind"
	"server/app/lib"
)

type (
	// Logic
	// 基础逻辑.
	Logic struct{}

	CategoryStats struct {
		Id         int64 `xorm:"id"`
		GoodsTotal int   `xorm:"goods_total"`
		GoodsCount int   `xorm:"goods_count"`
	}
	StockState struct {
		GoodsId kind.GoodsId    `xorm:"goods_id"`
		Stock   kind.GoodsStock `xorm:"stock"`
	}
)

// BuildFinanceRecords
// 构建财务流水记录.
func (o *Logic) BuildFinanceRecords(ctx context.Context, sess *db.Session, arcade *models.Arcades, admin *models.ArcadeAdmins, goods *models.Goods, purchase *models.GoodsPurchase) (err error) {
	var (
		ca *models.ArcadeCalendar
		fk = kind.FinanceKindPurchase
	)

	// 1. 添加流水.
	if _, err = services.NewArcadeFinanceService(sess).Add(ctx, &models.ArcadeFinance{
		ArcadeId: arcade.Id,
		Date:     db.NewDate(),
		UserId:   admin.UserId,
		Type:     kind.FinanceTypeExpense,
		Cost:     purchase.PurchaseCost,
		Kind:     fk,
		Params:   fmt.Sprintf(`{"Id":%d,"PurchaseId":%d}`, goods.Id, purchase.Id),
		Message:  fk.ToPurchase(purchase.PurchaseCount, goods.Unit, purchase.PurchaseCost, goods.Name),
	}); err != nil {
		return
	}

	// 2. 更新日历
	if ca, err = lib.Arcade.GetMaster().InitCalendar(ctx, arcade.Id); err == nil {
		_, err = services.NewArcadeCalendarService(sess).IncrExpense(
			ctx,
			ca.Id,
			purchase.PurchaseCost,
		)
	}
	return
}

// CalcCategory
// 分类计算.
func (o *Logic) CalcCategory(ctx context.Context, sess *db.Session, aid kind.ArcadeId) (err error) {
	var (
		list    []*CategoryStats
		service *services.GoodsCategoryService
		t1      = (&models.Goods{}).TableName()
		t2      = (&models.GoodsCategory{}).TableName()
	)
	if err = sess.SQL(fmt.Sprintf(`SELECT c.id, 
       IFNULL(x.goods_total, 0) AS goods_total, 
			 IFNULL(x.goods_count, 0) AS goods_count 
FROM %s c LEFT JOIN (
	SELECT g.category_id,
				 COUNT(*) AS goods_total,
				 SUM(IF(g.state=1,1,0)) AS goods_count
	FROM %s g 
	WHERE g.arcade_id = '%d' AND g.deleted = 0
	GROUP BY g.category_id
) x ON x.category_id = c.id WHERE c.arcade_id = '%d'`, t2, t1, aid, aid)).Find(&list); err != nil {
		err = errs.ErrDatabaseQuery
		return
	}

	service = services.NewGoodsCategoryService()

	for _, item := range list {
		if _, err = service.Dao.UpdateFieldsById(ctx, map[string]any{
			"goods_total": item.GoodsTotal,
			"goods_count": item.GoodsCount,
		}, item.Id); err != nil {
			err = errs.ErrDatabaseQuery
			break
		}
	}
	return
}

// CalcForSale
// 计算上架数.
func (o *Logic) CalcForSale(sess *db.Session, aid kind.ArcadeId) (count int64, err error) {
	if count, err = sess.Where("arcade_id = ? AND deleted = ? AND state = ?",
		aid, kind.DeletedNo, kind.GoodsStateForSale,
	).Count(models.Goods{}); err != nil {
		err = errs.ErrDatabaseQuery
	}
	return
}

// CalcTotal
// 计算总数.
func (o *Logic) CalcTotal(sess *db.Session, aid kind.ArcadeId) (count int64, err error) {
	if count, err = sess.Where("arcade_id = ? AND deleted = ?",
		aid, kind.DeletedNo,
	).Count(models.Goods{}); err != nil {
		err = errs.ErrDatabaseQuery
	}
	return
}

// CalcUpdate
// 保存统计.
func (o *Logic) CalcUpdate(sess *db.Session, aid kind.ArcadeId, total, sales int64) (err error) {
	if _, err = sess.Cols("shop_total", "shop_count").Where("id = ?",
		aid,
	).Update(&models.Arcades{
		ShopTotal: int(total),
		ShopCount: int(sales),
	}); err != nil {
		err = errs.ErrDatabaseQuery
	}
	return
}

// UpdateGoodsStock
// 计算库存量.
func (o *Logic) UpdateGoodsStock(ctx context.Context, sess *db.Session, aid kind.ArcadeId, gid kind.GoodsId) (total kind.GoodsStock, err error) {
	var (
		list    []*StockState
		service *services.GoodsService
		t1      = (&models.GoodsPurchase{}).TableName()
	)

	// 1. 查询列表.
	if err = sess.SQL(fmt.Sprintf(`SELECT p.goods_id,
	     SUM(p.purchase_count - p.sale_count - p.locked_count) AS stock
FROM %s p 
WHERE p.arcade_id = %d AND p.goods_id = %d AND p.deleted = %d`, t1, aid, gid, kind.DeletedNo)).Find(&list); err != nil {
		err = errs.ErrDatabaseQuery
		return
	}

	// 2. 更新库存.
	service = services.NewGoodsService()

	// 3. 遍历商品.
	for _, item := range list {
		if item.Stock < 0 {
			item.Stock = 0
		}

		total = item.Stock

		if _, err = service.Dao.UpdateFieldsById(ctx, map[string]any{
			"stock": item.Stock,
		}, item.GoodsId); err != nil {
			err = errs.ErrDatabaseQuery
			break
		}
	}
	return
}
